#include <sstream>
#include <iomanip>
#include <time.h>
#include "logging.h"

#if !defined(_WIN32)
#include <sys/stat.h>
#include <sys/types.h>
#endif

namespace asce
{
	char* Logging::log_info[LOG_ERROR+1] = {"--INFO--", "--WARNING--", "--ERROR--"};

	Logging::Logging()
	{
		max_log_size_ = 10;
		disk_full_ = false;
		to_stderr_ = true;
		file_severity_ = LOG_WARNING;
		stderr_severity_ = LOG_INFO;

#if defined(_WIN32)
		dir_ = "./log/";
		if (0 == CreateDirectory(dir_.c_str(), NULL))
		{
			if (ERROR_ALREADY_EXISTS != GetLastError())
			{
				dir_ = "";
			}
		}
#else
		if (-1 == mkdir(dir_.c_str(), S_IRWXU | S_IRWXG | S_IRWXO))
		{
			if (EEXIST != errno)
			{
				dir_ = "";
			}
		}
#endif
	}

	Logging::~Logging()
	{
		file_.Close();
	}

	Logging& Logging::Instance()
	{
		static Logging log;
		return log;
	}

	void Logging::Write(LogSevervity severiry, char* format, ...)
	{
		char buffer[2048] = {0};
		std::string str = GetNowTime();
		int num = sprintf_s(buffer, 2048, "%s   %s  ", log_info[severiry], str.c_str());

		va_list arg_ptr;
		va_start(arg_ptr, format);
		num += vsprintf_s(buffer+num, 2048-num, format, arg_ptr);
		va_end(arg_ptr);
		buffer[num] = '\n';
		++num;

		WriteMutexLock lock(mutex_);
		if (!file_.valid() && !CreatFile())
		{
			return ;
		}

		uint32 length = file_.length();
		if (static_cast<int>(length >> 20) >= max_log_size_ && !CreatFile())
		{
			return ;
		}

		if (severiry >= file_severity_)
		{
			file_.Write(buffer, num);
		}
		
		if (to_stderr_ && severiry >= stderr_severity_)
		{
			fwrite(buffer, sizeof(char), num, stderr);
		}
	}

	bool Logging::ToStdErr()
	{
		ReadMutexLock lock(mutex_);
		return to_stderr_;
	}

	void Logging::OpenToStdErr()
	{
		WriteMutexLock lock(mutex_);
		to_stderr_ = true;
	}

	void Logging::CloseToStdErr()
	{
		WriteMutexLock lock(mutex_);
		to_stderr_ = false;
	}

	uint32 Logging::GetMaxLogSize()
	{
		ReadMutexLock lock(mutex_);
		return max_log_size_;
	}

	LogSevervity Logging::FileSeveriry()
	{
		ReadMutexLock lock(mutex_);
		return file_severity_;
	}

	void Logging::SetFileSeverity(LogSevervity severity)
	{
		WriteMutexLock lock(mutex_);
		file_severity_ = severity;
	}

	LogSevervity Logging::StderrSeverity()
	{
		ReadMutexLock lock(mutex_);
		return stderr_severity_;
	}

	void Logging::SetStderrSeveriry(LogSevervity severity)
	{
		WriteMutexLock lock(mutex_);
		stderr_severity_ = severity;
	}

	void Logging::SetMaxLogSize(uint32 size)
	{
		WriteMutexLock lock(mutex_);
		max_log_size_ = size;

		uint32 length = file_.length();
		if (static_cast<int>(length >> 20) >= max_log_size_)
		{
			CreatFile();
		}
	}

	bool Logging::CreatFile()
	{
		std::string name = dir_ + GetNowTime() + ".log";

		if (file_.valid())
		{
			file_.Close();
		}

		return file_.Open(name);
	}

	std::string Logging::GetNowTime()
	{
		time_t now = time(NULL);
		tm tm_time;
		localtime_s(&tm_time, &now);

		std::ostringstream time_str;
		time_str.fill('0');
		time_str<< 1900+tm_time.tm_year
				<<std::setw(2) << 1+tm_time.tm_mon
				<<std::setw(2) << tm_time.tm_mday
				<< '-'
				<<std::setw(2) << tm_time.tm_hour
				<<std::setw(2) << tm_time.tm_min
				<<std::setw(2) << tm_time.tm_sec;


		return time_str.str();
	}
}
